/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef __ROCKCHIP_REG_H__
#define __ROCKCHIP_REG_H__

/* bit field helpers. */
#define __M(n)                      (~(~0<<(n)))
#define __RBF(number, n)            ((number)&__M(n))
#define __BF(number, n, m)          __RBF((number>>m), (n-m+1))
#define REG_BF(number, n, m)        (m<n ? __BF(number, n, m) : __BF(number, m, n))

#if 1
#define readb(reg)                  (*((volatile unsigned char *)(reg)))
#define readw(reg)                  (*((volatile unsigned short *)(reg)))
#define readl(reg)                  (*((volatile unsigned int *)(reg)))
#define readq(reg)                  (*((volatile unsigned long long *)(reg)))

#define writeb(data, reg)           ((*((volatile unsigned char *)(reg))) = (unsigned char)(data))
#define writew(data, reg)           ((*((volatile unsigned short *)(reg))) = (unsigned short)(data))
#define writel(data, reg)           ((*((volatile unsigned int *)(reg))) = (unsigned int)(data))
#define writeq(data, reg)           ((*((volatile unsigned long long *)(reg))) = (unsigned long long)(data))

#define mb()                        __asm__ __volatile__("mb": : :"memory")
#define rmb()                       __asm__ __volatile__("mb": : :"memory")
#define wmb()                       __asm__ __volatile__("wmb": : :"memory")
#else
#define __arch_getb(a)              (*(volatile unsigned char *)(a))
#define __arch_getw(a)              (*(volatile unsigned short *)(a))
#define __arch_getl(a)              (*(volatile unsigned int *)(a))
#define __arch_getq(a)              (*(volatile unsigned long long *)(a))

#define __arch_putb(v,a)            (*(volatile unsigned char *)(a) = (v))
#define __arch_putw(v,a)            (*(volatile unsigned short *)(a) = (v))
#define __arch_putl(v,a)            (*(volatile unsigned int *)(a) = (v))
#define __arch_putq(v,a)            (*(volatile unsigned long long *)(a) = (v))

#define ISB                         asm volatile ("isb sy" : : : "memory")
#define DSB                         asm volatile ("dsb sy" : : : "memory")
#define DMB                         asm volatile ("dmb sy" : : : "memory")

#define isb()                       ISB
#define dsb()                       DSB
#define dmb()                       DMB

#define mb()                        dsb()
#define __iormb()                   dmb()
#define __iowmb()                   dmb()

#define writeb(v,c)                 ({ rt_uint8_t  __v = v; __iowmb(); __arch_putb(__v,c); __v; })
#define writew(v,c)                 ({ rt_uint16_t __v = v; __iowmb(); __arch_putw(__v,c); __v; })
#define writel(v,c)                 ({ rt_uint32_t __v = v; __iowmb(); __arch_putl(__v,c); __v; })
#define writeq(v,c)                 ({ rt_uint64_t __v = v; __iowmb(); __arch_putq(__v,c); __v; })

#define readb(c)                    ({ rt_uint8_t  __v = __arch_getb(c); __iormb(); __v; })
#define readw(c)                    ({ rt_uint16_t __v = __arch_getw(c); __iormb(); __v; })
#define readl(c)                    ({ rt_uint32_t __v = __arch_getl(c); __iormb(); __v; })
#define readq(c)                    ({ rt_uint64_t __v = __arch_getq(c); __iormb(); __v; })
#endif

#define clrsetreg(addr, clr, set) writel(((clr) | (set)) << 16 | (set), addr)
#define clrreg(addr, clr)         writel((clr) << 16, addr)
#define setreg(addr, set)         writel((set) << 16 | (set), addr)

#define SET_BIT(REG, x)                     ((REG) |= 1 << (x))
#define CLEAR_BIT(REG, x)                   ((REG) &= ~(1 << (x)))

#define DIV_ROUND_UP(n,d)         (((n) + (d) - 1) / (d))

#define DUMP_REG(base, bit, reg)                   \
do {                                               \
    rt_uint32_t status = 0x00000000;               \
    status = readl(base + reg);                    \
    rt_kprintf("%-*.*s ", bit, bit, #reg);         \
    rt_kprintf("%p 0x%.8x\n", base + reg, status); \
} while(0);

#define RK_MIN(x, y) ({                            \
    typeof(x) _min1 = (x);                         \
    typeof(y) _min2 = (y);                         \
    (void) (&_min1 == &_min2);                     \
    _min1 < _min2 ? _min1 : _min2; })

#define RK_MAX(x, y) ({                            \
    typeof(x) _max1 = (x);                         \
    typeof(y) _max2 = (y);                         \
    (void) (&_max1 == &_max2);                     \
    _max1 > _max2 ? _max1 : _max2; })

#define RK_MIN3(x, y, z) RK_MIN((typeof(x))RK_MIN(x, y), z)
#define RK_MAX3(x, y, z) RK_MAX((typeof(x))RK_MAX(x, y), z)

#endif /* __ROCKCHIP_REG_H__ */